package hardcode2013;

import com.google.appengine.api.datastore.*;
import com.google.appengine.api.datastore.Query.*;

import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;

import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class MailServ extends HttpServlet {
	private static final long serialVersionUID = 1L;
	
	public static final int resultsPerPage = 50;
	
	public static List<ConversationProfile> getUserConversations(String username) {
	    DatastoreService datastore = DatastoreServiceFactory.getDatastoreService();
	    Query query = new Query("Message");
	    query = query.setFilter(new CompositeFilter(CompositeFilterOperator.OR, Arrays.<Filter>asList(
	    		new FilterPredicate("sender", FilterOperator.EQUAL, username),
	    		new FilterPredicate("recipient", FilterOperator.EQUAL, username)
	    		)));
	    query = query.addSort("creation_datetime", Query.SortDirection.DESCENDING);;
	    QueryResultList<Entity> queryResList = datastore.prepare(query).asQueryResultList(FetchOptions.Builder.withDefaults());
	    
	    List<ConversationProfile> conversationList = new ArrayList<ConversationProfile>();
	    for (Entity e : queryResList) {
	    	MessageProfile msg = new MessageProfile(
	    			KeyFactory.keyToString(e.getKey()),
	    			(e.getProperty("item_key") != null ? (String) e.getProperty("item_key") : null),
					(e.getProperty("item_price") != null ? (String) e.getProperty("item_price") : null),
	    			(String) e.getProperty("sender"),
	    			(String) e.getProperty("recipient"),
	    			new SimpleDateFormat("yyyy-MM-dd HH:mm").format(new Date((Long) e.getProperty("creation_datetime"))),
	    			(String) e.getProperty("title"),
	    			(String) e.getProperty("content"),
	    			Boolean.valueOf(String.valueOf(e.getProperty("is_read"))));
	    	
	    	String partner = (msg.getSender().equals(username) ? msg.getRecipient() : msg.getSender());
	    	boolean exists = false;
	    	for (ConversationProfile c : conversationList) {
	    		if ((c.getItemKeyStr() == null && msg.getItemKeyStr() == null && (c.getStarter().equals(partner) || c.getResponder().equals(partner))) ||
	    				(c.getItemKeyStr() != null && msg.getItemKeyStr() != null && c.getItemKeyStr().equals(msg.getItemKeyStr()))) {
	    			exists = true;
					c.setItemPrice(msg.getItemPrice());
	    			c.setStarter(msg.getSender());
	    			c.setResponder(msg.getRecipient());
	    			c.setCreationDateTime(msg.getCreationDateTime());
	    			c.setMessagesCount(c.getMessagesCount() + 1);
	    		}
	    	}    	
	    	if (! exists) {
    			conversationList.add(new ConversationProfile(
    					msg.getItemKeyStr(),
						msg.getItemPrice(),
    					msg.getSender(),
    					msg.getRecipient(),
    					msg.getCreationDateTime(),
    					msg.getCreationDateTime(),
    					msg.getSender(),
    					msg.getIsRead(),
    					1));
	    	}
	    }
	    return conversationList;
	}
	
	public static List<MessageProfile> getMessages(String username, String partner, String itemKeyStr) {
		  DatastoreService datastore = DatastoreServiceFactory.getDatastoreService();
		    Query query = new Query("Message");
		    query = query.setFilter(new CompositeFilter(CompositeFilterOperator.AND, Arrays.<Filter>asList(
		    		new CompositeFilter(CompositeFilterOperator.OR, Arrays.<Filter>asList(
			    		new CompositeFilter(CompositeFilterOperator.AND, Arrays.<Filter>asList(
			    				new FilterPredicate("sender", FilterOperator.EQUAL, username),
			    				new FilterPredicate("recipient", FilterOperator.EQUAL, partner))),
			    		new CompositeFilter(CompositeFilterOperator.AND, Arrays.<Filter>asList(
			    				new FilterPredicate("sender", FilterOperator.EQUAL, partner),
			    				new FilterPredicate("recipient", FilterOperator.EQUAL, username))))),
    				new FilterPredicate("item_key", FilterOperator.EQUAL, itemKeyStr)
		    		)));
		    query = query.addSort("creation_datetime", Query.SortDirection.DESCENDING);;
		    QueryResultList<Entity> queryResList = datastore.prepare(query).asQueryResultList(FetchOptions.Builder.withDefaults());
		    
		    List<MessageProfile> messageList = new ArrayList<MessageProfile>();
		    for (Entity e : queryResList) {
		    	MessageProfile msg = new MessageProfile(
		    			KeyFactory.keyToString(e.getKey()),
		    			(e.getProperty("item_key") != null ? (String) e.getProperty("item_key") : null),
						(e.getProperty("item_price") != null ? (String) e.getProperty("item_price") : null),
		    			(String) e.getProperty("sender"),
		    			(String) e.getProperty("recipient"),
		    			new SimpleDateFormat("yyyy-MM-dd HH:mm").format(new Date((Long) e.getProperty("creation_datetime"))),
		    			(String) e.getProperty("title"),
		    			(String) e.getProperty("content"),
		    			Boolean.valueOf(String.valueOf(e.getProperty("is_read"))));
		    	messageList.add(msg);
		    }
		    
		    if (messageList.size() > 0) {
		    	MessageProfile lastMsg = messageList.get(0);
		    	if (! lastMsg.getIsRead() && lastMsg.getRecipient().equals(username)) markAsRead(lastMsg);
		    }
		    
		    return messageList;
	}
	public static List<MessageProfile> getMessages(String username, String partner, Key itemKey) {
		return getMessages(username, partner, KeyFactory.keyToString(itemKey));
	}
	
	private static void markAsRead(MessageProfile msg) {
		Entity msgEn = getMessageEntity(msg.getkeyStr());
		if (msgEn != null) {
			msgEn.setProperty("is_read", true);
			DatastoreService datastore = DatastoreServiceFactory.getDatastoreService();
			datastore.put(msgEn);
		}
	}

	private static Entity getMessageEntity(Key msgKey) {
		DatastoreService datastore = DatastoreServiceFactory.getDatastoreService();
		try {
			return datastore.get(msgKey);
		} catch (Exception ex) {
			return null;
		}
	}
	private static Entity getMessageEntity(String msgKeyStr) {
		return getMessageEntity(KeyFactory.stringToKey(msgKeyStr));
	}
	
	public void doPost(HttpServletRequest req, HttpServletResponse resp) throws IOException {
		String action = req.getParameter("action");
		if (action == null) {HttpUtil.HomeRedirect(resp); return;}
		
		//--- Create Message--- : Member
		if (action.equals("create_message")) { //item_key?, recipient?, title, content
			
			//load
			String authKey = req.getParameter("auth_key");
			String username = SessionUtil.getAuthUsername(req);
			String itemKeyStr = req.getParameter("item_key");
			String recipient = req.getParameter("recipient");
			String title = req.getParameter("title");
			String content = req.getParameter("content");
			
			//check
			if (! SessionUtil.authUser(req, username, authKey))
				{HttpUtil.HomeRedirect(resp); return;}
			else if (content == null || content.trim().isEmpty())
				{HttpUtil.ExitWithMsg("Content cannot be empty.", req, resp); return;}
			else if ((itemKeyStr == null || itemKeyStr.isEmpty()) && (recipient == null || recipient.trim().isEmpty()))
				{HttpUtil.ExitWithMsg("Recipient cannot be empty.", req, resp); return;}
			boolean isUseItem = itemKeyStr != null && ! itemKeyStr.isEmpty();
			
			if (isUseItem) {
				ItemProfile item = ItemServ.getItemProfile(itemKeyStr);
				if (item == null)
					{HttpUtil.HomeRedirect(resp); return;}
								
				//perform
				Entity message = new Entity("Message");
				message.setProperty("item_key", itemKeyStr);
				message.setProperty("item_price", item.getPrice());
				message.setProperty("sender", username);
				message.setProperty("recipient", (item.getSeller().equals(username) ? recipient : item.getSeller()));
				message.setProperty("creation_datetime", new Date().getTime());
				message.setProperty("title", title.trim());
				message.setProperty("content", content.trim());
				message.setProperty("is_read", false);
				DatastoreService datastore = DatastoreServiceFactory.getDatastoreService();
				datastore.put(message);
				AdminServ.logEvent(username, "Created Message" + "\n" +
						"Recipient: " + item.getSeller() + "\n" +
						"Item: " + item.getTitle());
				
			} else {
				String recipientArr[] = recipient.split(",");
				String reciStr = "";
				List<String> finalList = new ArrayList<String>();
				for (String rec : recipientArr) {
					if (rec.trim().isEmpty())
						continue;
					else if (rec.trim().toLowerCase().equals(username.toLowerCase()))
						{HttpUtil.ExitWithMsg("You cannot send mail to yourself.", req, resp); return;}
					else if (! AccountServ.checkAccountExists(rec.trim()))
						{HttpUtil.ExitWithMsg("Invalid recipient: " + rec.trim() + ".", req, resp); return;}
					reciStr += (reciStr.equals("") ? "" : ", " + rec.trim());
					if (! finalList.contains(rec.trim()))
						finalList.add(rec.trim());
				}
				if (finalList.size() == 0)
					{HttpUtil.ExitWithMsg("No recipients to send to.", req, resp); return;}
				for (String rec : finalList) {
					//perform
					Entity message = new Entity("Message");
					message.setProperty("item_key", null);
					message.setProperty("item_price", null);
					message.setProperty("sender", username);
					message.setProperty("recipient", AccountServ.getUsernameCase(rec.trim()));
					message.setProperty("creation_datetime", new Date().getTime());
					message.setProperty("title", title.trim());
					message.setProperty("content", content.trim());
					message.setProperty("is_read", false);
					DatastoreService datastore = DatastoreServiceFactory.getDatastoreService();
					datastore.put(message);
					AdminServ.logEvent(username, "Created Message" + "\n" +
							"Recipient(s): " + reciStr + "\n" +
							"Item: -");
				}
			}
			
			SessionUtil.setMessage(req, "Message sent successfully.");
		}
		
		HttpUtil.FinalRedirect(req, resp);
	}
	
	public void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {
		String action = req.getParameter("action");
		if (action == null) {HttpUtil.HomeRedirect(resp); return;}
		
		//--- View conversation --- : Member
		if (action.equals("view_conversation")) { //partner, item_key
			//load
			String partner = req.getParameter("partner");
			String itemKeyStr = req.getParameter("item_key");
			
			//perform
			String convoUrl = "/conversation.jsp?partner=" + partner + (itemKeyStr != null && ! itemKeyStr.isEmpty() ? "&item_key=" + itemKeyStr : "");
			resp.sendRedirect(convoUrl); return;
		}
		
		HttpUtil.FinalRedirect(req, resp);
	}
}
